FastAPI ara katmanında uzmanlaşın. Bu kapsamlı rehber özel ara katman, kimlik doğrulama, günlük kaydı, hata yönetimi ve sağlam API'ler oluşturmak için en iyi uygulamaları kapsar.
Python FastAPI Ara Katmanı (Middleware): İstek ve Yanıt İşlemeye Kapsamlı Bir Rehber
Modern web geliştirme dünyasında, performans, güvenlik ve sürdürülebilirlik çok önemlidir. Python'ın FastAPI çerçevesi, inanılmaz hızı ve geliştirici dostu özellikleriyle hızla popülerlik kazanmıştır. En güçlü ancak bazen yanlış anlaşılan özelliklerinden biri ara katmandır (middleware). Ara katman, bir isteğin hedefine ulaşmadan veya bir yanıt istemciye geri gönderilmeden önce geliştiricilerin kod yürütmesine, verileri değiştirmesine ve kuralları uygulamasına olanak tanıyan istek ve yanıt işlemede önemli bir bağlantı görevi görür.
Bu kapsamlı kılavuz, FastAPI'ye yeni başlayanlardan anlayışlarını derinleştirmek isteyen deneyimli profesyonellere kadar küresel bir geliştirici kitlesi için tasarlanmıştır. Ara katmanın temel kavramlarını keşfedecek, özel çözümlerin nasıl oluşturulacağını gösterecek ve pratik, gerçek dünya kullanım örneklerini inceleyeceğiz. Sonunda, daha sağlam, güvenli ve verimli API'ler oluşturmak için ara katmanı kullanmaya hazır olacaksınız.
Web Çerçeveleri Bağlamında Ara Katman Nedir?
Koda dalmadan önce, kavramı anlamak önemlidir. Uygulamanızın istek-yanıt döngüsünü bir boru hattı veya bir montaj hattı olarak hayal edin. Bir istemci API'nize bir istek gönderdiğinde, bu istek anında uç nokta mantığınıza ulaşmaz. Bunun yerine, bir dizi işlem adımından geçer. Benzer şekilde, uç noktanız bir yanıt oluşturduğunda, istemciye ulaşmadan önce bu adımlardan geri geçer. Ara katman bileşenleri, boru hattındaki bu adımlardır.
Popüler bir benzetme soğan modelidir. Soğanın özü, uygulamanızın iş mantığıdır (uç nokta). Özü çevreleyen soğanın her katmanı bir ara katman parçasıdır. Bir isteğin öze ulaşmak için her dış katmanı soyması ve yanıtın aynı katmanlardan geri gitmesi gerekir. Her katman, içeri girerken isteği ve dışarı çıkarken yanıtı inceleyebilir ve değiştirebilir.
Esasen, ara katman, istek nesnesine, yanıt nesnesine ve uygulamanın istek-yanıt döngüsündeki bir sonraki ara katmana erişimi olan bir işlev veya sınıftır. Birincil amaçları şunlardır:
- Kod yürütme: Günlük kaydı veya performans izleme gibi her gelen istek için eylemler gerçekleştirin.
- İsteği ve yanıtı değiştirme: Başlıklar ekleyin, yanıt gövdelerini sıkıştırın veya veri biçimlerini dönüştürün.
- Döngüyü kısa devre yapma: İstek-yanıt döngüsünü erken sonlandırın. Örneğin, bir kimlik doğrulama ara katmanı, kimliği doğrulanmamış bir isteğin hedeflenen uç noktaya ulaşmadan önce engellenebilir.
- Genel sorunları yönetme: Hata işleme, CORS (Çapraz Kaynak Paylaşımı) ve oturum yönetimi gibi kesişen sorunları merkezi bir yerde ele alın.
FastAPI, ASGI (Asenkron Sunucu Ağ Geçidi Arayüzü) standardının sağlam bir uygulamasını sağlayan Starlette araç setinin üzerine kurulmuştur. Ara katman, ASGI'de temel bir kavramdır ve bu da onu FastAPI ekosisteminde birinci sınıf bir vatandaş yapar.
En Basit Biçim: Bir Dekorator ile FastAPI Ara Katmanı
FastAPI, @app.middleware("http") dekoratörünü kullanarak ara katman eklemenin basit bir yolunu sunar. Bu, her HTTP isteği için çalışması gereken basit, bağımsız mantık için mükemmeldir.
Klasik bir örnek oluşturalım: her istek için işlem süresini hesaplayan ve yanıt başlıklarına ekleyen bir ara katman. Bu, performans izleme için inanılmaz derecede kullanışlıdır.
Örnek: Bir İşlem Süresi Ara Katmanı
İlk olarak, FastAPI ve Uvicorn gibi bir ASGI sunucusunun kurulu olduğundan emin olun:
pip install fastapi uvicorn
Şimdi, main.py adlı bir dosyada kodu yazalım:
import time
from fastapi import FastAPI, Request
app = FastAPI()
# Ara katman işlevini tanımlayın
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
# İstek geldiğinde başlangıç zamanını kaydedin
start_time = time.time()
# Bir sonraki ara katmana veya uç noktaya geçin
response = await call_next(request)
# İşlem süresini hesaplayın
process_time = time.time() - start_time
# Özel başlığı yanıta ekleyin
response.headers["X-Process-Time"] = str(process_time)
return response
@app.get("/")
async def root():
# Biraz işi simüle edin
time.sleep(0.5)
return {"message": "Merhaba Dünya!"}
Bu uygulamayı çalıştırmak için şu komutu kullanın:
uvicorn main:app --reload
Şimdi, cURL gibi bir araç veya Postman gibi bir API istemcisi kullanarak http://127.0.0.1:8000 adresine bir istek gönderirseniz, yanıtta yaklaşık 0,5 saniye değerinde yeni bir başlık olan X-Process-Time göreceksiniz.
Kodun Yapısı:
@app.middleware("http"): Bu dekoratör, işlevimizi bir HTTP ara katmanı olarak kaydeder.async def add_process_time_header(request: Request, call_next):: Ara katman işlevi asenkron olmalıdır. GelenRequestnesnesini ve özel bir işlev olancall_nextöğesini alır.response = await call_next(request): Bu en kritik satırdır.call_next, isteği boru hattındaki bir sonraki adıma (başka bir ara katman veya gerçek yol işlemi) geçirir. Bu çağrıyı beklemelisiniz. Sonuç, uç nokta tarafından oluşturulanResponsenesnesidir.response.headers[...] = ...: Yanıt uç noktadan alındıktan sonra, bu durumda özel bir başlık ekleyerek değiştirebiliriz.return response: Son olarak, değiştirilmiş yanıt istemciye gönderilmek üzere döndürülür.
Sınıflarla Kendi Özel Ara Katmanınızı Oluşturma
Dekoratör yaklaşımı basit olsa da, özellikle ara katmanınız yapılandırma gerektirdiğinde veya bazı iç durumları yönetmesi gerektiğinde daha karmaşık senaryolar için sınırlayıcı olabilir. Bu durumlarda, FastAPI (Starlette aracılığıyla) BaseHTTPMiddleware kullanarak sınıf tabanlı ara katmanı destekler.
Sınıf tabanlı bir yaklaşım daha iyi yapı sunar, yapıcısında bağımlılık eklemeye izin verir ve genellikle karmaşık mantık için daha sürdürülebilirdir. Temel mantık, asenkron bir dispatch yönteminde bulunur.
Örnek: Sınıf Tabanlı Bir API Anahtarı Kimlik Doğrulama Ara Katmanı
API'mizi güvenceye alan daha pratik bir ara katman oluşturalım. Belirli bir başlığı, X-API-Key'i kontrol edecek ve anahtar yoksa veya geçersizse, hemen bir 403 Forbidden hata yanıtı döndürecektir. Bu, isteği "kısa devre yapma" örneğidir.
main.py içinde:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.responses import Response
# Geçerli API anahtarlarının bir listesi. Gerçek bir uygulamada, bu bir veritabanından veya güvenli bir kasadan gelir.
VALID_API_KEYS = ["my-super-secret-key", "another-valid-key"]
class APIKeyMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
api_key = request.headers.get("X-API-Key")
if api_key not in VALID_API_KEYS:
# İsteği kısa devre yapın ve bir hata yanıtı döndürün
return JSONResponse(
status_code=403,
content={"detail": "Yasak: Geçersiz veya eksik API Anahtarı"}
)
# Anahtar geçerliyse, isteğe devam edin
response = await call_next(request)
return response
app = FastAPI()
# Ara katmanı uygulamaya ekleyin
app.add_middleware(APIKeyMiddleware)
@app.get("/")
async def root():
return {"message": "Güvenli bölgeye hoş geldiniz!"}
Şimdi, bu uygulamayı çalıştırdığınızda:
X-API-Keybaşlığı olmayan (veya yanlış bir değere sahip) bir istek, 403 durum kodu ve JSON hata mesajını alacaktır.X-API-Key: my-super-secret-keybaşlığı olan bir istek başarılı olacak ve 200 OK yanıtını alacaktır.
Bu model son derece güçlüdür. / adresindeki uç nokta kodunun API anahtarı doğrulaması hakkında hiçbir şey bilmesine gerek yoktur; bu sorun tamamen ara katman katmanına ayrılmıştır.
Ara Katman İçin Yaygın ve Güçlü Kullanım Durumları
Ara katman, kesişen sorunları ele almak için mükemmel bir araçtır. En yaygın ve etkili kullanım durumlarından bazılarını keşfedelim.
1. Merkezi Günlük Kaydı
Kapsamlı günlük kaydı, üretim uygulamaları için pazarlık konusu değildir. Ara katman, her istek ve karşılık gelen yanıtı hakkında kritik bilgileri kaydettiğiniz tek bir nokta oluşturmanıza olanak tanır.
Örnek Günlük Kaydı Ara Katmanı:
import logging
from fastapi import FastAPI, Request
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def logging_middleware(request: Request, call_next):
start_time = time.time()
# İstek ayrıntılarını günlüğe kaydedin
logger.info(f"Gelen istek: {request.method} {request.url.path}")
response = await call_next(request)
process_time = time.time() - start_time
# Yanıt ayrıntılarını günlüğe kaydedin
logger.info(f"Yanıt durumu: {response.status_code} | İşlem süresi: {process_time:.4f}s")
return response
Bu ara katman, isteğin yöntemini ve yolunu, içeri girerken ve yanıt durum kodunu ve toplam işlem süresini dışarı çıkarken günlüğe kaydeder. Bu, uygulamanızın trafiğine paha biçilmez bir görünürlük sağlar.
2. Küresel Hata İşleme
Varsayılan olarak, kodunuzdaki işlenmemiş bir özel durum, potansiyel olarak yığın izlemelerini ve uygulama ayrıntılarını istemciye açığa çıkararak 500 İç Sunucu Hatasıyla sonuçlanır. Küresel bir hata işleme ara katmanı, tüm özel durumları yakalayabilir, dahili inceleme için günlüğe kaydedebilir ve standartlaştırılmış, kullanıcı dostu bir hata yanıtı döndürebilir.
Örnek Hata İşleme Ara Katmanı:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import logging
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def error_handling_middleware(request: Request, call_next):
try:
return await call_next(request)
except Exception as e:
logger.error(f"İşlenmemiş bir hata oluştu: {e}", exc_info=True)
return JSONResponse(
status_code=500,
content={"detail": "Bir iç sunucu hatası oluştu. Lütfen daha sonra tekrar deneyin."}
)
@app.get("/error")
async def cause_error():
return 1 / 0 # Bu bir ZeroDivisionError oluşturacaktır
Bu ara katmanla, /error adresine yapılan bir istek artık sunucuyu çökertmeyecek veya yığın izlemesini açığa çıkarmayacaktır. Bunun yerine, geliştiricilerin araştırması için tam hata sunucu tarafında günlüğe kaydedilirken, temiz bir JSON gövdesiyle sorunsuz bir şekilde 500 durum kodu döndürecektir.
3. CORS (Çapraz Kaynak Paylaşımı)
Ön uç uygulamanız FastAPI arka ucundan farklı bir etki alanından, protokolden veya bağlantı noktasından sunuluyorsa, tarayıcılar Aynı Kaynak İlkesi nedeniyle istekleri engelleyecektir. CORS, bu ilkeyi gevşetme mekanizmasıdır. FastAPI, bu amaç için özel, son derece yapılandırılabilir bir `CORSMiddleware` sağlar.
Örnek CORS Yapılandırması:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# İzin verilen kaynakların listesini tanımlayın. Genel API'ler için "*" kullanın, ancak daha iyi güvenlik için belirli olun.
origins = [
"http://localhost:3000",
"https://my-production-frontend.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True, # Çapraz kaynak isteklerine tanımlama bilgilerinin dahil edilmesine izin verin
allow_methods=["*"], # Tüm standart HTTP yöntemlerine izin verin
allow_headers=["*"], # Tüm başlıklarına izin verin
)
Bu, ayrılmış bir ön uca sahip herhangi bir projeye ekleyeceğiniz ilk ara katman parçalarından biridir ve çapraz kaynak ilkelerini tek, merkezi bir konumdan yönetmeyi kolaylaştırır.
4. GZip Sıkıştırması
HTTP yanıtlarını sıkıştırmak, boyutlarını önemli ölçüde azaltabilir ve bu da istemciler için daha hızlı yükleme sürelerine ve daha düşük bant genişliği maliyetlerine yol açar. FastAPI, bunu otomatik olarak işlemek için bir `GZipMiddleware` içerir.
Örnek GZip Ara Katmanı:
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
# GZip ara katmanını ekleyin. Sıkıştırma için minimum bir boyut ayarlayabilirsiniz.
app.add_middleware(GZipMiddleware, minimum_size=1000)
@app.get("/")
async def root():
# Bu yanıt küçüktür ve gziplenmeyecektir.
return {"message": "Merhaba Dünya"}
@app.get("/large-data")
async def large_data():
# Bu büyük yanıt, ara katman tarafından otomatik olarak gziplenecektir.
return {"data": "a_very_long_string..." * 1000}
Bu ara katmanla, istemci GZip kodlamasını kabul ettiğini belirtirse (neredeyse tüm modern tarayıcılar ve istemciler gibi) 1000 bayttan büyük herhangi bir yanıt sıkıştırılır.
Gelişmiş Kavramlar ve En İyi Uygulamalar
Ara katmanda daha yetkin hale geldikçe, temiz, verimli ve tahmin edilebilir kod yazmak için bazı nüansları ve en iyi uygulamaları anlamak önemlidir.
1. Ara Katman Sırası Önemlidir!
Bu, hatırlamanız gereken en kritik kuraldır. Ara katman, uygulamaya eklendiği sırayla işlenir. Eklenen ilk ara katman, "soğanın" en dış katmanıdır.
Bu kurulumu göz önünde bulundurun:
app.add_middleware(ErrorHandlingMiddleware) # En dış
app.add_middleware(LoggingMiddleware)
app.add_middleware(AuthenticationMiddleware) # En iç
Bir isteğin akışı şu şekilde olacaktır:
ErrorHandlingMiddlewareisteği alır.call_nextöğesini birtry...exceptbloğuna sarar.LoggingMiddleware'e isteği iletereknext'i çağırır.LoggingMiddlewareisteği alır, günlüğe kaydeder venext'i çağırır.AuthenticationMiddlewareisteği alır, kimlik bilgilerini doğrular venext'i çağırır.- İstek sonunda uç noktaya ulaşır.
- Uç nokta bir yanıt döndürür.
AuthenticationMiddlewareyanıtı alır ve yukarı geçirir.LoggingMiddlewareyanıtı alır, günlüğe kaydeder ve yukarı geçirir.ErrorHandlingMiddlewareson yanıtı alır ve istemciye döndürür.
Bu sıra mantıklıdır: hata işleyicisi dışarıdadır, böylece diğer ara katman dahil olmak üzere herhangi bir sonraki katmandan gelen hataları yakalayabilir. Kimlik doğrulama katmanı içeride derindedir, bu nedenle reddedilecek istekleri günlüğe kaydetme veya işleme konusunda endişelenmiyoruz.
2. `request.state` ile Veri Geçirme
Bazen, bir ara katmanın uç noktaya bilgi geçirmesi gerekir. Örneğin, bir kimlik doğrulama ara katmanı bir JWT'yi çözebilir ve kullanıcının kimliğini çıkarabilir. Bu kullanıcı kimliği yol işlemi işlevine nasıl sunulabilir?
Yanlış yol, istek nesnesini doğrudan değiştirmektir. Doğru yol, request.state nesnesini kullanmaktır. Bu tam olarak bu amaç için sağlanan basit, boş bir nesnedir.
Örnek: Ara Katmandan Kullanıcı Verilerini Geçirme
# Kimlik doğrulama ara katmanınızın gönderme yönteminde:
# ... belirteci doğruladıktan ve kullanıcının kodunu çözdükten sonra ...
user_data = {"id": 123, "username": "global_dev"}
request.state.user = user_data
response = await call_next(request)
# Uç noktanızda:
@app.get("/profile")
async def get_user_profile(request: Request):
current_user = request.state.user
return {"profile_for": current_user}
Bu, mantığı temiz tutar ve `Request` nesnesinin ad alanını kirletmekten kaçınır.
3. Performans Hususları
Ara katman güçlü olsa da, her katman az miktarda ek yük ekler. Yüksek performanslı uygulamalar için bu noktaları aklınızda bulundurun:
- Sade tutun: Ara katman mantığı olabildiğince hızlı ve verimli olmalıdır.
- Asenkron olun: Ara katmanınızın G/Ç işlemleri (bir veritabanı kontrolü gibi) gerçekleştirmesi gerekiyorsa, sunucunun olay döngüsünü engellememek için tamamen `async` olduğundan emin olun.
- Amaçla kullanın: İhtiyacınız olmayan ara katman eklemeyin. Her biri çağrı yığını derinliğine ve işlem süresine katkıda bulunur.
4. Ara Katmanınızı Test Etme
Ara katman, uygulamanızın mantığının kritik bir parçasıdır ve kapsamlı bir şekilde test edilmelidir. FastAPI'nin `TestClient` bunu kolaylaştırır. Gerekli koşullarla (örneğin, geçerli bir API anahtarıyla ve olmadan) istek gönderen ve ara katmanın beklendiği gibi davrandığını onaylayan testler yazabilirsiniz.
APIKeyMiddleware için Örnek Test:
from fastapi.testclient import TestClient
from .main import app # FastAPI uygulamanızı içe aktarın
client = TestClient(app)
def test_request_without_api_key_is_forbidden():
response = client.get("/")
assert response.status_code == 403
assert response.json() == {"detail": "Yasak: Geçersiz veya eksik API Anahtarı"}
def test_request_with_valid_api_key_is_successful():
headers = {"X-API-Key": "my-super-secret-key"}
response = client.get("/", headers=headers)
assert response.status_code == 200
assert response.json() == {"message": "Güvenli bölgeye hoş geldiniz!"}
Sonuç
FastAPI ara katmanı, modern web API'leri oluşturan herhangi bir geliştirici için temel ve güçlü bir araçtır. Kesişen sorunları ele almak için zarif ve yeniden kullanılabilir bir yol sağlayarak bunları temel iş mantığınızdan ayırır. Ara katman, her isteği ve yanıtı yakalayıp işleyerek sağlam günlük kaydı, merkezi hata işleme, katı güvenlik ilkeleri ve sıkıştırma gibi performans geliştirmeleri uygulamanıza olanak tanır.
Basit @app.middleware("http") dekoratöründen karmaşık, sınıf tabanlı çözümlere kadar, ihtiyaçlarınız için doğru yaklaşımı seçme esnekliğine sahipsiniz. Ara katman sıralaması ve durum yönetimi gibi temel kavramları, yaygın kullanım durumlarını ve en iyi uygulamaları anlayarak daha temiz, daha güvenli ve yüksek düzeyde sürdürülebilir FastAPI uygulamaları oluşturabilirsiniz.
Şimdi sıra sizde. Bir sonraki FastAPI projenize özel ara katmanı entegre etmeye başlayın ve API tasarımınızda yeni bir kontrol ve zarafet düzeyi elde edin. Olasılıklar çok büyük ve bu özellikte uzmanlaşmak şüphesiz sizi daha etkili ve verimli bir geliştirici yapacaktır.